package org.javacore.StreamsTutorial;

import org.apache.commons.lang3.RandomStringUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.function.IntUnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * Created by IntelliJ IDEA.
 * User: Fan
 * Date: 2018/6/30
 * Time: 16:45
 */
public class StreamTest {
    public static final String[] names = {"All","Math","English","Chinese","Art","null"};


    public static void main(String[] args) {
        //System.out.println(testFibonacci(3));
        testFabocci();
//        streamArrayTest();
//        streamArrayTest1();
        testPartitionBy();

    }


    /**
     * 使用Optional可以在没有值时指定一个返回值
     * 这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true，调用get()方法会返回该对象
     */
    public static void streamArrayTest(){
        Optional<String> str = Stream.of(names).filter(s->s.equals("all")).findFirst();
        if (str.isPresent()){
            System.out.println(str.get());
        }
    }

    public static void streamArrayTest0(){
        Stream.of(names).filter(s->s.equals("all")).sorted().findFirst().ifPresent(System.out::println);
    }

    public static void streamArrayTest1(){
        String stringStr = Stream.of(names).filter(s->s.equals("all")).sorted().findFirst().orElse("none");
        System.out.println(stringStr);
    }

    public static void mapTest(){
        Optional<String> optional = Stream.of(names).filter(name->"A".equals(name)).findAny().map(String::toUpperCase);
        if (optional.isPresent()){
            System.out.println(optional.get());
        }
    }

    public static void testStudent(){
        Random random = new Random();
        List<Student> students = new ArrayList<Student>(0){
            {
                      for (int i=0;i<100;i++){
                          add(new Student("Student"+i,random.nextInt(50)+50));
                      }
            }
        };

        String strings = students.stream()//转换为流
            .filter(x->x.getScore()>55)//条件过滤
            .sorted(Comparator.comparing(Student::getScore))//排序
            .map(Student::getName)//抽取属性,转换为新的流
            .collect(Collectors.joining(","));//将最终的list列表转换为字符串joining()
        System.out.println(strings);

    }

    /**
     * 创建无限流
     */
    public static void testUnlimitStream(){
        //创建无限流，通过limit提取指定大小
        Stream.generate(
            ()->"number"+new Random().nextInt()
        ).limit(10).forEach(System.out::println);
    }
    /**
     * 创建规律的无限流数据
     */
    public static void testUnlimitStream1(){
        List<Integer> integerList = Stream.iterate(0,x->x+1)
            .limit(10).collect(Collectors.toList());
            //.forEach(System.out::println);
        System.out.println(integerList);

        List<Integer> integerList1 = Stream.iterate(0,x->x+1)
            .limit(10).collect(Collectors.toList());
        //.forEach(System.out::println);
        System.out.println(integerList1);
    }

    public static int testFibonacci(int n){
        if (n==1 || n==2){
            return 1;
        }else{
            return (testFibonacci(n-1)+testFibonacci(n-2));
        }
    }

    /**
     * IntStream生成斐波拉契数列列表
     */
    public static void testCreateFibonacci(){
        IntStream  intStream = IntStream.iterate(1, new IntUnaryOperator() {
            private int prev = 0;
            @Override
            public int applyAsInt(int operand) {
                int temp = operand + prev;
                prev = operand;
                return temp;
            }
        });

        List<Integer> integerList = intStream
            .limit(20)  //抽取前20条数据
            .boxed().   //装箱
                collect(Collectors.toList());   //聚集转换为list列表
        System.out.println(integerList);
    }

    /**
     * 求列表元素的最大数
     */
    public static void getMaxOfList(){
        List<Integer> list = new Random().ints(0,100)   //创建一个int类型的随机数字流，这些数字在0到99之间
            .limit(10)  //抽取流中的前10个数
            .boxed()    //装箱
            .collect(Collectors.toList());  //聚集转换为list列表
        System.out.println("=======打印输出的随机数列表===="+list);
        Optional<Integer> max = list.stream()
            .max(Comparator.comparing(integer -> integer));     //从list列表中取出最大的那个int数
        if (max.isPresent()){
            System.out.println("========随机数列表最大数===="+max.get());
        }
    }

    /**
     * 从列表中过滤找出指定的数据
     *
     * 使用peek()方法可以对stream带有lambda表达式的操作进行调试---------便于观察中间结果，调试改错
     */
    public static void testFilterBy(){
        List<Student> students = new ArrayList<Student>(0){
            {
                for (int i=0;i<100;i++) {
                    add(new Student(RandomStringUtils.randomAlphanumeric(5), new Random().nextInt(100)));
                }
            }
        };
        System.out.println("=======打印输出的随机字母列表===="+students);

        String strings = students.stream()//转换为流
            .filter(x->x.getName().startsWith("C"))//条件过滤
            .peek(e-> System.out.println("=====filter value==="+e.getName()))
            .sorted(Comparator.comparing(Student::getScore))//排序
            .peek(e-> System.out.println("=====sort value==="+e.getName()))
            .map(Student::getName)//抽取属性,转换为新的流
            .peek(e-> System.out.println("=====map value==="+e))
            .collect(Collectors.joining(","));//将最终的list列表转换为字符串joining()
        System.out.println("=======输出过滤后的字符串===="+strings);

        //求平均分数
        Double studentD = students.stream().collect(Collectors.averagingInt(Student::getScore));
        System.out.println("=======输出学生平均分======"+studentD);
    }

    /**
     * groupingBy分组
     */
    public static void testGroupBy(){
        List<Student> students = new ArrayList<Student>(0){
            {
                for (int i=0;i<100;i++) {
                    add(new Student(RandomStringUtils.randomAlphanumeric(5), new Random().nextInt(100)));
                }
            }
        };
        System.out.println("=======打印输出的随机字母列表===="+students);
        Map<String, List<Student>> studentList = students.stream().collect(Collectors.groupingBy(Student::getName));
        System.out.println("=======打印输出的分组后字母列表===="+studentList);
    }

    /**
     * partitioningBy分片
     */
    public static void testPartitionBy(){
        List<Student> students = new ArrayList<Student>(0){
            {
                for (int i=0;i<100;i++) {
                    add(new Student(RandomStringUtils.randomAlphanumeric(5), new Random().nextInt(100)));
                }
            }
        };
        System.out.println("=======打印输出的随机字母列表===="+students);
        Map<Boolean,List<Student>> booleanListMap = students.stream().collect(Collectors.partitioningBy(student->student.getScore()>60));
        System.out.println("=======打印分区后的数据列表===="+booleanListMap);
    }

    /**
     * 分组+聚合
     */
    public static void testDownstream(){
        List<Student> students = new ArrayList<Student>(0){
            {
                for (int i=0;i<100;i++) {
                    add(new Student(RandomStringUtils.randomAlphanumeric(5), new Random().nextInt(100)));
                }
            }
        };
        System.out.println("=======打印输出的随机字母列表===="+students);

        //每个学生所获总分summingInt
        Map<String, Integer> studentList = students.stream().collect(Collectors.groupingBy(Student::getName,Collectors.summingInt(Student::getScore)));
        System.out.println("=======打印输出的分组后每个学生所获总分列表===="+studentList);

        //每个学生，分组后个数counting
        Map<String, Long> studentLists = students.stream().collect(Collectors.groupingBy(Student::getName,Collectors.counting()));
        System.out.println("=======打印输出的分组后每个学生，分组后个数列表===="+studentLists);

        //每个学生，分组后数据排序maxBy
        Map<String, Optional<Student>> studentLists1 = students.stream().collect(Collectors.groupingBy(Student::getName,Collectors.maxBy(Comparator.comparing(Student::getScore))));
        System.out.println("=======打印输出的分组后每个学生，分组后数据排序列表===="+studentLists1);

        //每个学生，分组后数据映射mapping
        Map<String, Set<Student>> studentLists2 = students.stream().collect(Collectors.groupingBy(Student::getName,Collectors.toSet()));
        System.out.println("=======打印输出的分组后每个学生，分组后数据排序列表===="+studentLists2);

    }

    /**
     * 生成斐波拉契数列
     *
     *
     */
    public static void testFabocci(){
        List<Long> fibonacci = Stream.generate(new FibonacciSupplier()).limit(10).collect(Collectors.toList());
        System.out.println(fibonacci);
    }

}
